package com.net.okhttphelper.http;

import android.text.TextUtils;

import com.google.gson.Gson;
import com.net.okhttphelper.constant.RequestMethod;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.concurrent.ConcurrentHashMap;

/**
 * 请求参数构建类
 * 注意文件上传只支持post请求，并且上传文件时，requestBody字段设置无效
 * @author jie
 */
public class RequestParams {

    private final String tag;
    private final String url;
    private final String method;
    private final String requestBody;
    private final String saveDirPath;
    private final ConcurrentHashMap<String, String> queryParams;
    private final ConcurrentHashMap<String, String> headerParams;
    private final ConcurrentHashMap<String, String> fileParams;

    public static RequestParams.Builder builder(String url, String tag){
        return new RequestParams.Builder(url, tag);
    }

    public RequestParams.Builder newBuilder(){
        return new RequestParams.Builder(this);
    }

    private RequestParams(){
        throw new IllegalArgumentException("不能使用该构造方法");
    }

    private RequestParams(Builder builder) {
        this.tag = builder.tag;
        this.url = builder.url;
        this.method = builder.method;
        this.requestBody = builder.requestBody;
        this.queryParams = builder.queryParams;
        this.headerParams = builder.headerParams;
        this.fileParams = builder.fileParams;
        this.saveDirPath = builder.saveDirPath;
    }

    public String getTag() {
        return tag;
    }

    public String getUrl() {
        return url;
    }

    public String getMethod() {
        return method;
    }

    public String getRequestBody() {
        return requestBody;
    }

    public ConcurrentHashMap<String, String> getQueryParams() {
        return queryParams;
    }

    public ConcurrentHashMap<String, String> getHeaderParams() {
        return headerParams;
    }

    public ConcurrentHashMap<String, String> getFileParams() {
        return fileParams;
    }

    public String getSaveDirPath() {
        return saveDirPath;
    }

    public static class Builder {
        // 用于解析requestBody的实体参数
        private static final Gson GSON = new Gson();

        private final String url; // 请求路径
        private final String tag; // 请求标识
        private String method = RequestMethod.GET; // 请求方式，默认为Get
        private String requestBody; // 请求body参数（json格式）
        private String saveDirPath; // 文件下载到本地文件夹地址
        private ConcurrentHashMap<String, String> queryParams = new ConcurrentHashMap<>(); // 路径中的查询参数集合
        private ConcurrentHashMap<String, String> headerParams = new ConcurrentHashMap<>(); // 请求头参数集合
        private ConcurrentHashMap<String, String> fileParams = new ConcurrentHashMap<>(); // 文件上传参数集合

        /**
         * 因为url和tag为必填项，故在构造方法中设定值
         * @param url 请求路径
         * @param tag 请求标识，用于取消请求
         */
        private Builder(String url, String tag){
            if (TextUtils.isEmpty(url) || tag == null){
                throw new NullPointerException("request url or tag is null !");
            }
            this.url = url;
            this.tag = tag;
        }

        private Builder(RequestParams requestParams){
            this.tag = requestParams.tag;
            this.url = requestParams.url;
            this.method = requestParams.method;
            this.requestBody = requestParams.requestBody;
            this.queryParams = requestParams.queryParams;
            this.headerParams = requestParams.headerParams;
            this.fileParams = requestParams.fileParams;
            this.saveDirPath = requestParams.saveDirPath;
        }

        public Builder get(){
            this.method = RequestMethod.GET;
            return this;
        }

        public Builder post(){
            this.method = RequestMethod.POST;
            return this;
        }

        public Builder put(){
            this.method = RequestMethod.PUT;
            return this;
        }

        public Builder delete(){
            this.method = RequestMethod.DELETE;
            return this;
        }

        /**
         * 设置requestBody参数（会覆盖原来的参数）
         */
        public Builder requestBody(String requestBody) {
            this.requestBody = requestBody;
            return this;
        }

        /**
         * 设置requestBody参数（会覆盖原来的参数）
         */
        public <T> Builder requestBodyObj(T requestBodyObj){
            this.requestBody = GSON.toJson(requestBodyObj);
            return this;
        }

        /**
         * 往requestBody中追加一个参数（不会覆盖原来的参数）
         */
        public Builder putBody(String key, Object value){
            if (key != null && value != null){
                try {
                    JSONObject jsonObject;
                    if (!TextUtils.isEmpty(requestBody)){
                        jsonObject = new JSONObject(requestBody);
                    }else{
                        jsonObject = new JSONObject();
                    }
                    jsonObject.put(key, value);
                    requestBody = jsonObject.toString();
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
            return this;
        }

        /**
         * 追加一个查询参数
         */
        public Builder putQuery(String key, String value) {
            if (key != null && value != null) {
                queryParams.put(key, value);
            }
            return this;
        }

        /**
         * 追加一个请求头参数
         */
        public Builder putHeader(String key, String value){
            if (key != null && value != null){
                headerParams.put(key, value);
            }
            return this;
        }

        /**
         * 追加一个文件参数
         * @param key 对应服务器文件上传key
         * @param filePath 文件本地路径
         */
        public Builder putFile(String key, String filePath){
            if (key != null && filePath != null){
                fileParams.put(key, filePath);
            }
            return this;
        }

        /**
         * 设置文件下载到本地文件夹地址
         */
        public Builder setSaveDirPath(String saveDirPath){
            this.saveDirPath = saveDirPath;
            return this;
        }

        public RequestParams build() {
            return new RequestParams(this);
        }
    }

}
